package interview.juc;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 三个线程循环打印ABC. 要求同时开始执行线程，并且要A先打印
 * 分别用 Lock 和 sync 实现
 *
 * 重点：
 * 一个锁
 * 死循环条件等待 wait()
 * 执行完当前任务之后 notifyAll()
 * 退出条件
 *
 *
 * Created by yzy on 2021-01-18 19:06
 */
public class ThreadLoopPrintOne {

    static int threadNum = 3;
    static int printNum = 0;    // 打印字母数
    static int loopNum = 10;    // 循环打印10次
    static CyclicBarrier cb = new CyclicBarrier(threadNum);

    public static void main(String[] args) {
//        TestLockThread tl1 = new TestLockThread(0,"A");
//        TestLockThread tl2 = new TestLockThread(1,"B");
//        TestLockThread tl3 = new TestLockThread(2,"C");
//
//        tl2.start();
//        tl1.start();
//        tl3.start();

        TestSyncThread ts1 = new TestSyncThread(0, "A");
        TestSyncThread ts2 = new TestSyncThread(1, "B");
        TestSyncThread ts3 = new TestSyncThread(2, "C");

        ts2.start();
        ts1.start();
        ts3.start();

    }


    static final Object syncObj = new Object();
    static class TestSyncThread extends Thread{
        private int currNum;
        private String str;

        public TestSyncThread(int n, String s){
            this.currNum = n;
            this.str = s;
        }

        @Override
        public void run(){
            try {
                System.out.println("Thread:"+currNum + " is waiting...");
                cb.await();
                System.out.println("Thread:"+currNum + " is started");
            } catch (Exception e) {
                e.printStackTrace();
            }

            for(int i=0; i<loopNum; i++){
                synchronized (syncObj){
                    try {
                        while (printNum%threadNum != currNum) {
                            syncObj.wait();
                        }
                        System.out.println("SyncThread:"+ currNum + " print:"+str);
                        printNum++;
                        syncObj.notifyAll();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }
        }
    }


    static Lock lock = new ReentrantLock();
    static Condition con = lock.newCondition();
    static class TestLockThread extends Thread{
        private int currNum;    // 线程标记顺序
        private String str;     // 打印字符串

        public TestLockThread(int n, String s){
            this.currNum=n;
            this.str=s;
        }

        @Override
        public void run(){
            try {
                System.out.println("Thread:" + currNum + " is waiting...");
                cb.await();
                System.out.println("Thread:" + currNum + " is started");
            } catch (Exception e) {
                e.printStackTrace();
            }

            for(int i=0; i<loopNum; i++){
                lock.lock();
                try {
                    // 条件等待循环
                    while (printNum%threadNum != currNum) {
                        con.await();
                    }
                    System.out.println("Thread:" + currNum + " print:" + str);
                    printNum++;
                    con.signalAll();
                } catch (Exception e){
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }

        }
    }
}
